/**
 * 
 */
package ru.assa.signalka;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Random;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

import android.app.PendingIntent;
import android.app.PendingIntent.CanceledException;
import android.app.Service;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.content.Intent;
import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
import android.os.ResultReceiver;
import android.util.Log;
import android.view.ViewDebug.IntToString;

/**
 * @author assa
 *
 */
public class BluetoothService extends Service {


private String LOG_TAG = "BluetothServise";
private BluetoothAdapter _bluetooth = BluetoothAdapter.getDefaultAdapter(); 
private BluetoothDevice _remotedevice ; // = _bluetooth.getRemoteDevice(getString(R.string.bluetoothdevice));
//private BluetoothDevice _remotedevice = _bluetooth.getRemoteDevice("00:0B:0D:33:6A:FF");

private BluetoothSocket socket = null;
private OutputStream outputStream;
private InputStream inputStream;
private PendingIntent pi;
private Bt bt;
private Input input;
private Output output;
private ResultReceiver receiver;
private ArrayList<ServiceCallbackListener> currentListeners = new ArrayList<ServiceCallbackListener>();

public static BluetoothService BS;

public static BluetoothService getBS() {
	return BS;
}

public static boolean CONNECTED = false;

		  @Override
		public void onCreate() {
		    super.onCreate();
			BS = this;
		    Log.d(LOG_TAG, "MyService onCreate");

			bt = new Bt();
		  } //onCreate
		  
		  @Override
		  public IBinder onBind(Intent intent) { 

		    return new Binder();
		  }
		  
		  @Override
		public int onStartCommand(Intent intent, int flags, int startId) { //TODO Убрать ненужные флаги

			    Log.d(LOG_TAG, "onStartCommand");
//			    bt.connect();
			    String command = intent.getStringExtra("command");
			    String val = intent.getStringExtra("value");
//			    receiver = getReceiver(intent);
			    Log.d(LOG_TAG, command);
			    Log.d(LOG_TAG, val);
			     if (command.equals("updatek")) { //Обработка входящих комманд switch String в андроид нет
			       	 if (CONNECTED){
			    		 sendToActiviti("connected", "1"); //TODO дописать проверку соединения
			    	 } else {
			    		 bt.connect();
			    	 }
			     } else {
			    	 Log.d(LOG_TAG, "COMMAND NOT FOUND");
			    	 Random random = new Random();
			    	 int r = random.nextInt(2);
			    	 Log.d("RANDOM", String.valueOf(r));
			    	 try {
						TimeUnit.SECONDS.sleep(random.nextInt(5));
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
			    	 sendToActiviti(command, String.valueOf(r) );
//			    	 sendToActiviti("dor_on", "1");
			     }
			    return super.onStartCommand(intent, flags, startId);
			  }
		  
			private String getCommand(Intent intent) {
				return intent.getStringExtra("command"); 
			}
			
			private String getValue(Intent intent) {
				return intent.getStringExtra("value"); 
			}
			
			private ResultReceiver getReceiver(Intent intent) {
				return intent.getParcelableExtra("receiver"); //TODO Передать сюда контекст получить значение из ресурса
			}
		  
		public void addListener(ServiceCallbackListener currentListener) {
				Log.d(LOG_TAG, "Listener adeded");
		    	currentListeners.add(currentListener);
//		    	sendToActiviti("хрень", "Хрень");
		        }

		public void removeListener(ServiceCallbackListener currentListener) {
		    	currentListeners.remove(currentListener);
		        }
			
		  public void sendToActiviti(String command , String val){
			    for (ServiceCallbackListener currentListener : currentListeners) {
					if (currentListener != null) currentListener.onServiceCallback(1, command, val);
				}
//				Bundle data = new Bundle();
//			    data.putString("command", command); //TODO Передать сюда контекст получить значение из ресурса
//			    data.putString("value", val);
//				receiver.send(-1 , data ); //TODO Отправляем нужен ли мне код возврата? 
		  }
//		  public void onRebind(Intent intent) {
//		    super.onRebind(intent);
//		    Log.d(LOG_TAG, "MyService onRebind");
//		  }
//		  
//		  public boolean onUnbind(Intent intent) {
//		    Log.d(LOG_TAG, "MyService onUnbind");
//		    return super.onUnbind(intent);
//		  }
		  
		  @Override
		public void onDestroy() {
		    super.onDestroy();
		    Log.d(LOG_TAG, "MyService onDestroy");
		    if(bt != null){bt.disconnect();}
		  }
		  
		  class Input implements Runnable {
			  
			  private Thread t;
			  
			  public void start() //Запускает новый поток
			  {
				  Log.d(LOG_TAG, "Input start");
				  if ( inputStream == null ) {
					  t = new Thread(this, "Input");
					  t.start(); //Запускает run()
				  } else {
					  Log.d(LOG_TAG, "input run");
				  }
			  }
			  
			  public void stop()
			  {
				  t.stop(); //останавливает поток
				  try {
					inputStream.close();

				} catch (IOException e) {
					inputStream = null;
					e.printStackTrace();
				}
					bt.disconnect();
			  }
			  
				 @Override
				public void run() 
				 {
					    byte[] buffer = new byte[1024];  //XXX буферный массив нужно 10 байт
					    int bytes; // bytes returned from read()
					    StringBuilder command_build = new StringBuilder();
					    String command = null;
					    String val;
					    boolean command_flag = true;
					    // Прослушиваем InputStream пока не произойдет исключение
					    while (true) //Бесконечный цикл постоянно проверяет есть ли сообщение
					    {
					    	Log.d(LOG_TAG, "while");
					        try {
					        	inputStream = socket.getInputStream();
					            // читаем из InputStream 1024 байта и отдаём в хендлер
					            bytes = inputStream.read(buffer);
					        } catch (IOException e) {
						    	Log.d(LOG_TAG, "input IOException");
					        	stop();
					            break; //Завершает цикл убивает поток 
					        }
					        Log.d(LOG_TAG, "bytes - " + bytes);
				            for (int i = 0; i < bytes; i++) {
				            	//command_build.append(buffer[i]);
				            	if ( buffer[i] == ',' ) {
				            		command_flag=false;
//				            		command_build.append(";"); //Временно тест
					            	command = command_build.toString(); //Команда готова
					            	Log.d(LOG_TAG, "command - " + command);
				            		continue; //запятая не нужна
				            	} else 
				            	if ( buffer[i] == ';' || buffer[i] == '\n' ) {
				            		command_flag=true;
				            		command_build = null;
				            		command = null; //Новая команда началась старую прибеваем
				            		val = null;
				            		continue; //точка с запятой и энтер не нужен
				            	} else
				            	if ( command_flag == true ) {
				            		String s = String.valueOf(buffer[i]);
				            		command_build.append(s);

				            	} else {
				            		val = Byte.toString(buffer[i]);
				            		command = command_build.toString(); //преобразование в String
				            		Log.d(LOG_TAG, "val - " + val);
				            		
				            		sendToActiviti(command, val);
				    			    
				            		command_flag=true;
				            		command_build = null;
				            		command = null; //Новая команда началась старую прибеваем
				            		val = null;
							}
					    }
				}
		  }
		  }
		  
		  class Output implements Runnable {
			  private String msg;
			  private Thread t;
			  
			  public void send(String msg){
				  this.msg=msg;
				  t = new Thread(this, "Output");
				  t.start(); //Запускает run()
			  }
			  
			  public void stop()
			  {
				  t.stop(); //останавливает поток
				  try {
					  outputStream.close();
				} catch (IOException e) {
					outputStream = null;
					e.printStackTrace();
				}
					bt.disconnect();
			  }

			  @Override
			public void run() {
				if (CONNECTED){
				try {
					outputStream = socket.getOutputStream();
			        outputStream.write(msg.getBytes("CP1251"));
			    } catch (IOException e) {
			    	//ХХХ тут реально может упасть хз что писать может статический класс???
			    	stop();
			    	bt.disconnect();
			    }
				}else{
					  Log.d(LOG_TAG, "not connected");
				}
			}
			}
		  
		  class Bt implements Runnable {
			  private Thread t;
			  
			  public void connect() {
					if ( _bluetooth == null) { 
						Log.d(LOG_TAG, "Adapter not found");
						disconnect();
						return;
						}
					if (!_bluetooth.isEnabled()) { 
//					    Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); //Неуверен что мне нужен запрос на включение
//					    startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
//						disconnect();
						Log.d(LOG_TAG, "Adapder disable");
						disconnect();
						return; 
					}
				  if (CONNECTED) return; //если подключено ничего не делать
				  _remotedevice = _bluetooth.getRemoteDevice("00:0B:0D:33:6A:FF");
				  t = new Thread(this, "Connect"); //Запускается новый поток сразу из конструктора
				  t.start(); //Запускает run()
				  Log.d(LOG_TAG, "connect start");

			}
			  public void disconnect(){
				  	sendToActiviti("connected", "0"); //Посылаем сигнал в управляющее активити
				    if(input != null){input.stop();}
				    if(output != null){output.stop();}
					CONNECTED = false;
					if (socket != null){
						try {
							socket.close();
						} catch (IOException e) {
							Log.d(LOG_TAG, "socket.close faled");
							socket = null;
							e.printStackTrace();
						}
					}
			  }
			  
			  @Override
			public void run(){
				if (!CONNECTED) {
				try {
					socket = _remotedevice.createRfcommSocketToServiceRecord(UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"));
					socket.connect();
				    Log.d(LOG_TAG, "Connect soket connected");

					CONNECTED = true;
					input = new Input(); //Сконструировали новый объект
				  	input.start(); //Стартует поток принимающий сообщения
				} catch (IOException e) { 
					disconnect();
//					outputStream = null; //XXX не уверен что это правильно
//					outputStream = null; 
//					CONNECTED = false;
				}
				}else{
			    	Log.d(LOG_TAG, "allredy connected");
				}
			}
		  }
		  
}
